package spzx.service.impl;

import cn.hutool.captcha.CircleCaptcha;
import cn.hutool.crypto.digest.DigestUtil;
import com.alibaba.fastjson.JSON;
import com.atguigu.spzx.model.dto.system.LoginDto;
import com.atguigu.spzx.model.dto.system.SysUserDto;
import com.atguigu.spzx.model.entity.system.SysUser;
import com.atguigu.spzx.model.vo.system.LoginVo;
import com.atguigu.spzx.model.vo.system.ValidateCodeVo;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;
import org.springframework.util.StringUtils;
import spzx.exception.SpzxException;
import spzx.mapper.SysUserMapper;
import spzx.service.SysUserService;
import utils.SysUserThreadLocal;

import java.util.List;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Service
public class SysUserServiceImpl implements SysUserService {
    @Autowired
    private SysUserMapper sysUserMapper;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;//明儿去问问这玩意
    @Override
    public List<SysUser> findAll() {
        return sysUserMapper.findAll();
    }

    /**
     * 参数：UserName+Password
     * @param loginDto
     * @return
     */
    @Override
    public LoginVo login(LoginDto loginDto) {
        //0.校验验证码
        String captcha = loginDto.getCaptcha();
        //从redis中查询正确的验证码
        String codeKey = loginDto.getCodeKey();
        String codeFromRedis = stringRedisTemplate.opsForValue().get(codeKey);
        if(StringUtils.isEmpty(codeFromRedis)) {
            throw new SpzxException(501,"验证码已过期");
        }
        if(!captcha.equals(codeFromRedis)){
            throw new SpzxException(501,"验证码错误");
        }

        //1.参数数据的非空校验，若某个值为空，抛出SpzxException并返回错误信息
        String userName = loginDto.getUserName();
        String password = loginDto.getPassword();
        //用户名和密码不能不写或者只写空格
        if (userName == null || userName.trim().length() == 0) {
            throw new SpzxException(501,"用户名不得为空");
        }
        if (password == null || password.trim().length() == 0) {
            throw new SpzxException(501,"密码不得为空");
        }
        //2.根据用户名查询用户信息
        SysUser sysUser = sysUserMapper.findByUserName(userName);
        //3.若用户信息不存在，报SpzxException并返回错误信息
        if (sysUser == null) {
            throw new SpzxException(510,"用户不存在");
        }
        //4.若用户信息存在，校验密码是否正确。注意：数据库的密码是经过MD5加密过的
        //   若密码不正确，抛出异常，给出相应的异常信息
        String passwordFromDb = sysUser.getPassword();
        //对某个字符串进行MD5加密
        //String md5Password = DigestUtils.md5DigestAsHex(password.getBytes());
        if (!passwordFromDb.equals(DigestUtils.md5DigestAsHex(password.getBytes()))) {
            throw new SpzxException(501,"密码错误");
        }
        //5.检验当前用户的状态是否被禁用，若被禁用，抛出相应的异常信息
        if(sysUser.getStatus() == 0){
            throw new SpzxException(501,"用户被禁用");
        }

        //6.将当前用户信息，转为json字符串，存储至redis中，ttl设置为30分钟，可以用来检验用户是否登录
        //token是一个能够保证唯一的字符串即可（uuid）,prefix = user:login
        // key = prefix + token
        // value = json字符串
        String token = UUID.randomUUID().toString().replaceAll("-", "");
        String prefix = "user:login:";
        String key = prefix + token;
        //fastjson:将对象转换为json字符串
        String value = JSON.toJSONString(sysUser);
        stringRedisTemplate.opsForValue().set(key, value, 30, TimeUnit.MINUTES);
        //7.将token封装为一个LoginVo对象，并给前端返回
        //前端拿到loginVo后,解析出token,存储至浏览器,后续前端发起请求调其他接口是，会将token放在请求头中传给后端
        //后端解析token,从redis中获取用户信息,并进行权限校验，查看是否登录
        LoginVo loginVo = new LoginVo();
        loginVo.setToken(token);
        return loginVo;

    }

    @Override
    public SysUser userInfo(String token) {
        System.out.println("service--> preHandle方法-->" + Thread.currentThread().getName());


        String key = "user:login:" + token;
        String jsonString = stringRedisTemplate.opsForValue().get(key);
        //将json字符串转为SysUser对象
        SysUser sysUser = JSON.parseObject(jsonString, SysUser.class);
        return sysUser;
    }

    @Override
    public void logout(String token) {
        String key = "user:login:" + token;
        stringRedisTemplate.delete(key);
    }

    @Override
    public ValidateCodeVo getValidateCode() {
        //1.借助hutool生成验证码图片对象
        CircleCaptcha circleCaptcha = new CircleCaptcha(150, 50, 4, 10);
        //2.从对象中获取图形字符串
        String imageBase64 = circleCaptcha.getImageBase64();
        //3.从对象中获取图形中的四位验证码
        String code = circleCaptcha.getCode();
        //4.将验证码存入redis中，key为uuid，value为验证码，有效期为5分钟
        String key = UUID.randomUUID().toString().replaceAll("-", "");
        stringRedisTemplate.opsForValue().set(key, code, 5, TimeUnit.MINUTES);

        ValidateCodeVo validateCodeVo = new ValidateCodeVo();
        validateCodeVo.setCodeValue("data:image/png;base64," + imageBase64);
        validateCodeVo.setCodeKey(key);
        return validateCodeVo;
    }

    @Override
    public PageInfo findByPage(Integer pageNum, Integer pageSize, SysUserDto sysUserDto) {
        //1.设置分页参数
        PageHelper.startPage(pageNum, pageSize);
        //2.查询数据(SELECT * FROM `sys_user` WHERE (username LIKE ? OR NAME LIKE ? ) AND create_time >= ? AND create_time <= ? AND is_delete = 0)
        List<SysUser> list = sysUserMapper.selectByCondition(sysUserDto);
        //3.封装PageInfo对象并返回
        return new PageInfo(list);
    }

    @Override
    public void addSysUser(SysUser sysUser) {
        sysUser.setPassword(DigestUtil.md5Hex(sysUser.getPassword()));
        sysUserMapper.addSysUser(sysUser);
    }

    @Override
    public void deleteById(Long sysUserId) {
        //检测下当前删除的用户是否是登陆状态，若是登录的用户，不得删除
        SysUser sysUser = SysUserThreadLocal.getSysUser();
        if(sysUser!= null && sysUser.getId() == sysUserId){
            throw new SpzxException(501,"不能删除当前已登陆用户");
        }

        sysUserMapper.deleteById(sysUserId);
    }

    @Override
    public String deleteByIds(List<Long> ids) {
        SysUser sysUser = SysUserThreadLocal.getSysUser();
        Long currentSysUserId = sysUser.getId();
        String message = "";

        //这次就不拼接SQL了，直接遍历所有Id,循环删除
        for (Long id : ids) {
            if(id == currentSysUserId){
                message = sysUser.getUserName() + "不能删除当前已登陆用户,其他用户删除成功";
                continue;
            }
            sysUserMapper.deleteById(id);
        }
        return message;
    }

    @Override
    public void updateSysUser(SysUser sysUser) {
        sysUserMapper.updateSysUser(sysUser);
    }
}
